package info.u250.c2d.box2d;

import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.QueryCallback;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.MouseJoint;
import com.badlogic.gdx.physics.box2d.joints.MouseJointDef;
import info.u250.c2d.engine.Engine;

/**
 * @author xjjdog
 */
public class MouseJointInput extends InputAdapter {

    Body fixBody;
    World world;

    public void setFixBody(Body fixBody) {
        this.fixBody = fixBody;
    }

    public void setWorld(World world) {
        this.world = world;
    }


    private MouseJoint mouseJoint = null;

    Body hitBody = null;


    /**
     * we instantiate this vector and the callback here so we don't irritate the GC
     **/
    Vector2 testPoint = new Vector2();
    QueryCallback callback = new QueryCallback() {
        @Override
        public boolean reportFixture(Fixture fixture) {
            // if the hit fixture's body is the ground body
            // we ignore it
            if (fixture.getBody() == fixBody) return true;

            // if the hit point is inside the fixture of the body
            // we report it
            if (fixture.testPoint(testPoint.x, testPoint.y)) {
                hitBody = fixture.getBody();
                return false;
            } else
                return true;
        }
    };

    @Override
    public boolean touchDown(int x, int y, int pointer, int newParam) {
        if (world == null) return false;
        // translate the mouse coordinates to world coordinates
        testPoint.set(Engine.screenToWorld(x, y).scl(1 / Box2dObject.RADIO));

        // ask the world which bodies are within the given
        // bounding box around the mouse pointer
        hitBody = null;
        world.QueryAABB(callback, testPoint.x - 0.1f, testPoint.y - 0.1f, testPoint.x + 0.1f, testPoint.y + 0.1f);

        // if we hit something we create a new mouse joint
        // and attach it to the hit body.
        if (hitBody != null) {
            MouseJointDef def = new MouseJointDef();
            def.bodyA = fixBody;
            def.bodyB = hitBody;
            def.collideConnected = true;
            def.target.set(testPoint.x, testPoint.y);
            def.maxForce = 1000.0f * hitBody.getMass();

            mouseJoint = (MouseJoint) world.createJoint(def);
            hitBody.setAwake(true);

            return true;
        }

        return false;
    }

    /**
     * another temporary vector
     **/
    Vector2 target = new Vector2();

    @Override
    public boolean touchDragged(int x, int y, int pointer) {
        // if a mouse joint exists we simply update
        // the target of the joint based on the new
        // mouse coordinates
        if (mouseJoint != null) {
            testPoint.set(Engine.screenToWorld(x, y).scl(1 / Box2dObject.RADIO));
            mouseJoint.setTarget(target.set(testPoint.x, testPoint.y));
            return true;
        }
        return false;
    }

    @Override
    public boolean touchUp(int x, int y, int pointer, int button) {
        // if a mouse joint exists we simply destroy it
        if (mouseJoint != null) {
            world.destroyJoint(mouseJoint);
            mouseJoint = null;
        }
        return false;
    }

}
